package org.NooLab.docserver;

 
import java.util.Map;

 
 

import org.NooLab.docserver.app.up.DocoServStartup;
import org.NooLab.docserver.app.up.IniProperties;

import org.NooLab.docserver.applet.DocumentObserverApplet;
import org.NooLab.docserver.main.DocumentObserverApplicationEventIntf;
import org.NooLab.docserver.main.DocumentObserverFactory;
import org.NooLab.docserver.properties.DocoControlProperties;
import org.NooLab.docserver.properties.DocoPropertiesHandler;
import org.NooLab.docserver.properties.DocumentObserverProperties;
import org.NooLab.docserver.properties.PersistenceSettings;
import org.NooLab.docserver.storage.DocoDataBase;
 
 
import org.NooLab.structures.AppInstanceAbstract;
import org.NooLab.structures.ArgumentsCliReaderAbstract;
import org.NooLab.structures.ArgumentsIntf;
import org.NooLab.structures.ArgumentsPublicIntf;

import org.NooLab.structures.InstanceProcessControlIntf;
import org.NooLab.utilities.files.DFutils;
import org.NooLab.utilities.files.PathFinder;
import org.NooLab.utilities.logging.LogControl;
import org.NooLab.utilities.logging.PrintLog;
import org.NooLab.utilities.resources.ResourceLoader;
import org.NooLab.utilities.strings.StringsUtil;


public class DocumentObserverApp {

	
	//=========================================================================
	public static void main(String[] args) {
		
		try {
		
			
			new DocumentObserverApp(args);
				
			
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		
	}

	//=========================================================================

	public DocumentObserverApp(String[] args){
		
		try {
			Class clzz = this.getClass() ;
			
			// System.out.println("self-id class : "+clzz.getSimpleName()+"\n");
			
			DocoServStartup.setApplicationID("DocServer", clzz);

			(new App( 0, (new Arguments()).parse(args), this.getClass())).go();
		
		} catch (Exception e) {
			e.printStackTrace();
		}
		 
	}
	
}

class App{

	int asService = 0;
	
	DocumentObserverApplet iapplet ;
	DocumentObserverInstance docoInstance;
	ArgumentsPublicIntf arguments;
	
	PrintLog out ;
	DFutils fileutil = new DFutils();

	// ========================================================================
	@SuppressWarnings("rawtypes")
	public App( int as_service, ArgumentsPublicIntf args, Class pubClass) {
		 
		String fname = "" ; 
		
		asService = as_service ;
		
		arguments = args;
		
		// use LogControl to control output of log messages
		LogControl.globeScope = 2; // 1=local definitions  default = 2
		LogControl.Level = 2 ;     // the larger the more detailed logging... (could be really verbose!)

		out = new PrintLog(2, true) ;
		
		boolean rB = checkForAppletMode();
		
		if (rB){
			return;
		}
		
		try {
			String lastCfgFile ="" ;
			
			DocoServStartup.setProjectSpaceLabel( arguments.getProjectName()) ;
			DocoServStartup.setLastProjectName(arguments.getProjectName());
			
			IniProperties.loadIniFile() ;
			
			lastCfgFile = DocoServStartup.getLastDataSet();
			if ((lastCfgFile==null) || (lastCfgFile.trim().length()<=1)){
				if (DocoServStartup.getApplicationID().length()==0 ){
					DocoServStartup.setApplicationID( this.getClass().getName().toLowerCase(),pubClass ) ;
				}
				
			}
			IniProperties.saveIniProperties() ;
			
			if (DFutils.fileExists(arguments.getConfigFile())==false){
				if ((arguments.getConfigFile().length()>0)){

					
					// lastCfgFile = IniProperties.dataSource ;
					if (arguments.getProjectName().length()==0){
						arguments.setProjectName("default") ;
					}
					
					fname = DFutils.createPath( arguments.getHomeDir(), arguments.getProjectName()+"/config/") ;
					fname = DFutils.createPath( fname, arguments.getConfigFile()) ;
					if (DFutils.fileExists(fname)){
						arguments.setConfigFile (fname);
					}else{
						if (fileutil.filenameIsUsable(fname)){
							arguments.setConfigFile (fname);
						}
					}
				}
				
				
				
				if (DFutils.fileExists(arguments.getConfigFile())==false){

					
					createDefaultConfig();

					
					String msgstr = "you now have to edit the configuration file : \n"+ arguments.getConfigFile();
					DocoServStartup.showMsg(msgstr);

					// DocoServStartup.introduceDataSet( arguments.configFile ) ;
			
					IniProperties.saveIniProperties() ;
					// copy the filename to the system clipboard
					System.exit(0);

				}else{
					
				}
				
			}
			
			IniProperties.saveIniProperties() ;
			
			_showCurrentInputSettings();
			
			
			fname=fname+" " ;
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}

	private boolean notStopped() {
		boolean rB=true; 
		
		String filename ;
		
		try{

			filename = arguments.getConfigFile() ;
			filename = StringsUtil.separateBeforeLast( filename, "/");
			filename = DFutils.createPath(filename, "stop") ;
			
			rB = DFutils.fileExists(filename)==false ;

			if (rB==false){
				fileutil.deleteFile(filename) ;
			}
		}catch(Exception e){
			
		}
		
		return rB;
	}

	private boolean checkForAppletMode() {

		boolean rB=false;
		
		if (arguments.startApplet() ){
		
			// start applet, stop this 
			// PApplet.main( new String[] { "org.NooLab.docserver.DocumentObserverApplet","a","b" });
			// PApplet applet = new PApplet();

			// see http://wiki.processing.org/w/Setting_width/height_dynamically
			iapplet = new DocumentObserverApplet();
			
			iapplet.getInstance() ;
			
			while (iapplet!=null){
				PrintLog.Delay(100);
			}
			rB=true;
		}
		return rB ;
	}

	private void createDefaultConfig() throws Exception {
		 
		String filename = "",  filstr,resourcePath;
		boolean rB;

		resourcePath = "org/NooLab/docserver/resources/docoserv-config-xml" ;
		ResourceLoader rsrcLoader = new ResourceLoader();   
		
		rB = rsrcLoader.loadTextResource( this.getClass(), resourcePath  ) ;
		if (rB){  
			filstr = rsrcLoader.getTextResource();
			
			filename = arguments.getConfigFile() ;
			
			fileutil.manageBakFile(filename, 10);
			fileutil.writeFileSimple( filename , filstr);
			
		}else{
			throw(new Exception("unable to load resources (create-db-sql-xml) or \n"+
					            "to create a new configuration file : "+filename)) ;
		}


		
	}

	// ========================================================================
	
	private void _showCurrentInputSettings(){
		String qs="";
		if (DocoServStartup.isConfigAvailable()==false){
			qs = "not " ;
		}
		// String dataStore = IniProperties.dataSource;
		// sth like: D:/data/iTexx/DocumentServer/test1/config/docoserv-config.xml
		
		
		out.print(2,"current project : "+ DocoServStartup.getLastProjectName());
		if (qs.length()==0){
			out.print(1,"config source   : "+ DocoServStartup.getLastDataSet() ) ;
		}

	}



	public void go() {
		
		notStopped();
		
		startEngines( asService );
		
		PrintLog.Delay(2000) ;
		// we stop from the outside by writing a file "stop" to the config directory
		while (notStopped()){
			PrintLog.Delay(100) ;
		}
		docoInstance.close(0) ;
	}

	/**
	 * 
	 * @param somtype 0=default: simple, single run; 1=som optimizer
	 * @param lastProjectName2 
	 */
	private void startEngines( int worktype ){
		int r;
		
		if (docoInstance!=null){
			return;
		}

		docoInstance = new DocumentObserverInstance( this, DocumentObserverFactory._GLUE_MODULE_ENV_NONE,"" ) ;

		
		
		if (arguments!=null){
			docoInstance.contextMode = arguments.getContextMode() ;
		
			docoInstance.homedir = arguments.getHomeDir() ;
			docoInstance.projectname = arguments.getProjectName() ;
			docoInstance.logLevel = arguments.getLogLevel();
			
			docoInstance.appSecret    = (String)arguments.getMappedTopic("appsecret"); 
			docoInstance.processName  = (String)arguments.getMappedTopic("name");
			docoInstance.setArguments( arguments.getArgumentsObj());
		}
		
		boolean hb = docoInstance.checkForConfiguration();
		
		if (hb==false){
			docoInstance.close(-5);
		}

		
		out.print(1,"starting project <"+ IniProperties.lastProjectName+"> ...");
		
		if (worktype<=1){
			worktype = DocumentObserverFactory._INSTANCE_TYPE_SERVICE ;
		}else{
			worktype = DocumentObserverFactory._INSTANCE_TYPE_EXPLICIT ;
		}
		 
							int oport = arguments.getOutPort();
							int iport = arguments.getInPort();
		
		r = docoInstance.prepareTcpBox(oport,iport);  // must be before the wait object !
		
		if (docoInstance.waitfor>=1){
			// waitfor-secret for testing is "adkhf-23487asdf-3487sdfr-324"
			out.print(2, "application will wait a few seconds for final clearance...");
			docoInstance.waitfor();
		}
		
		
		
		
		
		if (worktype>=0){
			docoInstance.startInstance(worktype) ;
		}
		
		
	}
	
}

@SuppressWarnings("rawtypes")
class Arguments extends ArgumentsCliReaderAbstract implements ArgumentsIntf{
	
	public final String _APP_COMPLETION_EXIT    = InstanceProcessControlIntf._APP_COMPLETION_EXIT ;
	public final String _APP_COMPLETION_SERVICE = InstanceProcessControlIntf._APP_COMPLETION_SERVICE ;
	
	public final String  _APP_CONTEXT_ITEXX = InstanceProcessControlIntf._APP_CONTEXT_ITEXX ;
	public final String  _APP_CONTEXT_ALONE = InstanceProcessControlIntf._APP_CONTEXT_ALONE ;
	
	
	String sourceFileDedicated="",sourceFilesByFolder="",sourceFileByListingFile="";
	
	protected ArgumentsPublicIntf arguments ;
	public Map argumentsMap;
	 
	
	// ------------------------------------------------------------------------
	@SuppressWarnings("unchecked")
	public Arguments(){
		super();
		setParent( this ) ;
	
		projectName = "docoserv";
		configFile  = "docoserv-config.xml";
		
		//default = standalone
		contextMode = InstanceProcessControlIntf._APP_CONTEXT_ALONE ; // itexx or standalone, running user based projects
		if (jarDir.toLowerCase().contains("itexx")){
			homeDir = DFutils.createPath( jarDir, "DocumentServer/") ;
		}
		jarDir = fileutil.getUserDir();
	}
	// ------------------------------------------------------------------------

	
	

	@SuppressWarnings("unchecked")
	@Override
	public ArgumentsPublicIntf parse( String[] _args ){
		
		String avStr, str;
		
		
		// jarDir = fileutil.getUserDir();
		str = fileutil.getUserHomeDir() ;
		str = IniProperties.fluidSomProjectBasePath; // before, we passed readbinpref() !
		homeDir = DFutils.createPath( str, "app/Astor/") ;
		
		/*
		 	-prj:itx  
		 	-homedir: D:/data/iTexx/app/DocumentServer/
		 	-cfg: docoserv-config.xml
		 	-context:itexx
		 	-waitfor:askdfh-876asdf-38-sf87sdsdfja
		 	-loglevel:2
		 	-comm: in-7215,out-7210
		 	-name:docObserver
		 */
		defineArguments( new String[]{ "prj","homedir","cfg",
				                       "context","waitfor",
				                       "comm",
				                       "loglevel"});
		
		try {
		
			arguments = prepareArguments( homeDir, _args ) ;

		} catch (Exception e) {
			showArguments( getDescription() );
			e.printStackTrace();
			System.exit(0);			
		}  

		argumentsMap = getArgumentsMap();
		
		
		
		if (handlingTreatment( new String[]{"prj","proj","project"})){
		
			projectName = (String)getMappedTopic( new String[]{"prj","proj","project"} );
			
			DocoServStartup.setLastProjectName(projectName);
			IniProperties.lastProjectName = projectName;
			IniProperties.saveIniProperties();
			
	 		
			str = IniProperties.getFluidSomProjectBasePath() ;
			if (IniProperties.getBinPath().length()==0){
				
				str = (new PathFinder()).getAppBinPath(this.getClass(), false);
				IniProperties.setBinPath(str) ;
			}
			
			IniProperties.saveIniProperties();
			str = IniProperties.getFluidSomProjectBasePath() ;
		}
		
		int rn = remainingTopics.size();
		
		// the rest
		if (rn>0){
			for (int i=0;i<rn;i++){
				String topic = (String) remainingTopics.get(i); 
				avStr = getArgumentValueStr( new String[]{topic} );
				if (avStr.length()>0){
					
					if (topic.toLowerCase().contentEquals("startsomclients")){
						// -startSomClients:1,7211,7210
						String[] scs = avStr.split(",") ;
						if (scs.length==3){
							if (strgutil.isNumericX(scs[0])){
								startSomClients = strgutil.getNumFromStr(scs[0], 0);
							}
							int portnum = 1;
							if (strgutil.isNumericX(scs[1])){
								portnum = strgutil.getNumFromStr(scs[1], 0);
								if (portnum>1090){
									inPort = portnum;  
								}
							}  
							if (strgutil.isNumericX(scs[2])){
								portnum = strgutil.getNumFromStr(scs[2], 0);
								if (portnum>1090){
									outPort = portnum;
								}
								
							}
						}
					}
				}// sth found
			}//i->
		}
		
		if (_args.length==0){
			showArguments( getDescription() );
			System.exit(0);
		}
		
		if (defaultsRequested){
			
			homeDir     = fileutil.createpath( fileutil.getUserDir(), "Astor") ;
			projectName = "itexx" ;
			configFile  = fileutil.createpath( homeDir, "astor-config.xml") ;
			// this file will be read by DocoControlProperties.readSettings()
		}
		
				
				
		setReference( (Object)this);
		return (ArgumentsPublicIntf) this;
	}
	
	 
	
	/*
	public Arguments parse( String[] _args ){
		String[] _arg ;
		String sep, avStr, str;
		
		if (_args.length==0){
			showArguments( getDescription() );
			System.exit(0);
		}
		ArrayList<String> args = new ArrayList<String>( Arrays.asList(_args));

		
		str = fileutil.getUserHomeDir() ;
		
		
		
		
		int k=0;
		while (k<args.size()){
			
			str = args.get(k).trim() ;
			if (str.startsWith("-")==false){
				if (k>0){
					if (args.get(k-1).endsWith(":")==false){
						sep=":";
					}else{
						sep=" ";
					}
					str = args.get(k-1) + sep + args.get(k);
					args.set(k-1,str) ;
					args.remove(k);
					k--;
				}
			}
			k++;
		}


		for (String argument : args){
			argument = argument.trim();
			
			_arg =argument.split(":") ;
			
			if ((_arg[0].length()>0) && (_arg[0].startsWith("-")) ){
				str = _arg[0].trim() ;
				str = str.substring(1,str.length()) ;
				
				avStr = "";
				if ((_arg.length>1) && (_arg[1].length()>0)){
					avStr = _arg[1].trim() ;
				}
				
				
				if (avStr.startsWith("\"")){
					avStr = avStr.substring(1,str.length()) ;
				}
				if (avStr.endsWith("\"")){
					avStr = avStr.substring(0,str.length()-1) ;
				}

				
				if ((str.contentEquals("p")) || str.contentEquals("prj") || str.contentEquals("proj") || str.contentEquals("project")){
					projectName = avStr;
					
					DocoServStartup.setLastProjectName(projectName);
					IniProperties.lastProjectName = projectName;
					IniProperties.saveIniProperties();
				}
				if ((str.contentEquals("h")) || (str.contentEquals("d")) || str.contentEquals("homedir") || (str.contentEquals("dir")) ){
					if (args.size()>2){
						avStr=avStr+":" ;
						for (int n=2;n<_arg.length;n++){
							if (_arg[n].length()>0){
								avStr= avStr + _arg[n] ;
								if (k<args.size()-1){
									avStr=avStr+":" ;			
								}
							}
						}
					}
					if (fileutil.direxists(avStr)){
						homeDir = avStr ;
					}
				}

				if (str.contentEquals("context") ){
					
					if (avStr.toLowerCase().contains("itexx")){
						contextMode = DocumentObserverProperties._APP_CONTEXT_ITEXX ;// = "itexx"; 
					}
					if (avStr.toLowerCase().contains("alone")){
						contextMode = DocumentObserverProperties._APP_CONTEXT_ALONE ;
					}
					
				}

				int vi;
				if (str.contentEquals("loglevel") ){  // default = 2
					
					if ((avStr.length()>0) &&(strgutil.isNumericX(avStr))){
						vi = Integer.parseInt(avStr) ; 
					}else{
						vi=2;
					}
					
					if ((vi>=0) && (vi<=5)){
						LogControl.Level = vi;
						logLevel = vi;
					}
				}
				
				if ((str.startsWith("n")) || str.contentEquals("notify")){
					
					// -notify:in-8988,out-8989
					String ports = avStr;
				}
				
				if ( ((str.startsWith("-c")) || str.contentEquals("cfg")) &&
					 (str.contentEquals("context")==false)){
					String cfgFile  = avStr; 
					if (DFutils.fileExists( cfgFile )==false){
						str = DFutils.createPath( homeDir, projectName+"/config/" ) ;
						cfgFile = DFutils.createPath( str , cfgFile) ;
						if (DFutils.fileExists( cfgFile ) ){
							configFile = cfgFile;
						}
					}else{
						configFile = cfgFile;
					}
				}
				

				if ((str.startsWith("a")) || str.contains("applet")){
					appletRequested  =true ;
				}
				
				if ((str.startsWith("d")) || str.contains("default")){
					defaultsRequested =true ;
				}
				
			} // _arg defined ?
			
		}// ->
		
		if (defaultsRequested){
			
			homeDir     = fileutil.createpath( fileutil.getUserDir(), "DocumentServer") ;
			projectName = "docoserv" ;
			configFile  = fileutil.createpath( homeDir, "docoserv-config.xml") ;
			// this file will be read by DocoControlProperties.readSettings()
		}
		
		return this;
	}
	*/
	/*
		-prj:"test2"
		-homedir:"D:/data/iTexx/DocumentServer"
		-cfg:"D:/data/iTexx/DocumentServer/test1/config/docoserv-config.xml"
	 */

	public boolean startApplet() {
		return appletRequested;
	}

	@Override
	public String get_APP_COMPLETION_EXIT() {
		return _APP_COMPLETION_EXIT;
	}

	@Override
	public String get_APP_COMPLETION_SERVICE() {
		return _APP_COMPLETION_SERVICE;
	}

	@Override
	public String get_APP_CONTEXT_ITEXX() {
		return _APP_CONTEXT_ITEXX;
	}

	@Override
	public String get_APP_CONTEXT_ALONE() {
		return _APP_CONTEXT_ALONE;
	}



	@Override
	public String[] getDescription() { 
		
		 
		String[] dParts = new String[3];
		String  defaults ,str;
		
		dParts[0] = "Values (examples) appear subsequent to the : \n"+
		        	"-prj:\"test2\"  \n"+
		        	"-homedir:\"D:/data/iTexx/DocumentServer\" \n"+
		        	"-cfg:\"D:/data/iTexx/DocumentServer/test1/config/docoserv-config.xml\" \n" ;

		dParts[1] = "Default values are activated by parameter \"-default\" or \"-d\" and are set to: \n"+
			        "-prj: docoserv  \n"+
					"-homedir: <path of jar>/DocumentServer \n"+
					"-cfg: <homedir>/<project name>/config/docoserv-config.xml  \n" +
					//"-context:itexx | standalone\n"+
					"\n"+
					"optional argument for providing notifications through TCP:\n"+
					"notify:8988,8989 \n";
		
		dParts[2] = "Additional Information: \n"+
		      "- The database file will be written to the folder \"<homedir>/<project name>/storage\".  \n"+
		      "- If no configuration file has been provided, a default file will be created into \n" +
		      "  the folder \"<homedir>/<project name>/config\". \n"+
		      "  Note that you then have to edit the configuration file, namely the section defining the \n"+
		      "  the folders to be observed.\n"+
		      "- You may stop the application by creating a file \"stop\" within the folder containing \n"+
		      "  the configuration file.  \n"+
		      "- The parameters for activating the notification are port numbers, (1) in, (2) out, where \n"+
		      "  the in-port allows for some udimaentary control, such like stopping the application, or \n"+
		      "  re-reading the configuration. \n"+
		      "- For starting the interactive applet version (e.g. for testing) use the \n"+
		      "  parameter \"-a\" or \"-applet\" \n\n"+" ";
		
		return dParts; 
	}

	@Override
	public int[] getPorts() {
		return ports;
	}

	@Override
	public int[] getServicePorts() {
		return this.servicePorts;
	}

	@Override
	public String getAppSecret() {
 		return appsecret;
	}
}



class DocumentObserverInstance  
									extends 
												AppInstanceAbstract 
									implements   
							  					// for messages from the engine to the outer application layers like this module
												DocumentObserverApplicationEventIntf{


	boolean keepRunning=true;
	public int logLevel;

	public String projectname;

	public String homedir;
	
	DocumentObserverFactory    docoFactory;
	DocumentObserverProperties docoProperties;
	DocoPropertiesHandler docoPropertiesDefaults;
	
	String sourceForProperties = "";
	 
	String lastProjectName;
	
	int instanceType;
	String contextMode = "" ;
	
	App app;
	
	
	// ------------------------------------------------------------------------
	public DocumentObserverInstance( App app, int gluemode, String propertiesSource ){
		
		super( "DocumentObserverApp", "DocoInstance");
		
		processName = "docoserv";
		
		this.app = app;
		
		sourceForProperties = propertiesSource;
 
		
		instance = this;
		out = app.out ;
		
		final Thread mainThread = Thread.currentThread();
		new OrganizedShutDown(mainThread);
	}


	public void startInstance( int worktype) {
	
		appSecret = app.arguments.getAppSecret() ;
		
		instanceType = worktype ;
		
		lastProjectName = IniProperties.lastProjectName ;
		instanceThrd.start();
	}


	@Override
	protected void prepareInstance() {

		try{
			
			if (instanceType > DocumentObserverFactory._INSTANCE_TYPE_DEFAULT){
				prepareDocumentObserver();
				createStartTask();
			}else{
				System.err.println("Can not start the instance using this type code ("+instanceType+").");
			}
			
		}catch(Exception e){
			e.printStackTrace();
		}

		
	}


	@Override
	protected void resumeInstance() throws Exception {
		
	}
	
	/*
	public void close(int exitcode) {
		docoFactory.close() ;
		if (processControl!=null){
			processControl.close(exitcode);
		}
		
	}
	 */
	 
	public boolean checkForConfiguration() {
		
	
			String prjname ="" ;
			// = docoProperties.getDocoControlProperties().getProjectName();
			
			prjname = IniProperties.lastProjectName; 
				
			String str = "unknown" ;
			
			if (prjname.length()==0){
				// ask for projectname
				try {
					
					DocoServStartup.selectActiveProject( 1 );
			
				} catch (Exception e) {
					e.printStackTrace();
				}
	
			}
	
			prjname = IniProperties.lastProjectName;
			
			return prjname.length()>0;
	}


	public void clearDataBaseTable(String tablename) {
		
		prepareDocumentObserver();
		docoFactory.getDocoDataBase().startServer();
		docoFactory.getDocoDataBase().clearTable(tablename) ;
	}

	public void startDataBaseServer() {
		prepareDocumentObserver();
		docoFactory.getDocoDataBase().startServer();
	}


	private void prepareDocumentObserver(){

		/*
		 * the basic scheme is always: 
		 * 		1. create properties object (is also loading), 
		 * 		2. create factory, prepare core instance
		 * 		3. start core instance, which contains a task loop
		 *      4. create a task
		 *      5. core will accept task and dispatch to respective objects
		 *      
		 *      
		 * only in this way we will get an application, that could always be on, if needed,
		 * and acting as a service
		 * 
		 */
		sourceForProperties = "" ;
		docoProperties = DocumentObserverProperties.getInstance( sourceForProperties );
		
		// alternatively... load from /resources in jar ...
		 
		docoProperties.setApplicationContext(contextMode) ;
		
		
		
		
		String systemroot = docoProperties.getSystemRootDir();   // [path]/iTexx
		
							PrintLog.Print(4,"\nsystemroot in properties first was : "+systemroot+"\n");
		
		if ( docoProperties.getApplicationContext().contentEquals( DocumentObserverProperties._APP_CONTEXT_ITEXX)){
			systemroot ="" ;
		}
		systemroot = adjustSystemRootFolder(systemroot,"itexx");
		
		systemroot = docoProperties.getSystemRootDir();
		
							PrintLog.Print(3,"\nsystemroot in properties is now : "+systemroot+"\n");
							PrintLog.Delay(1500);
		
		
		
		docoProperties.setInstanceType(0);

		docoProperties.getPersistenceSettings().setPathToSomFluidSystemRootDir(homedir);
		docoProperties.getPersistenceSettings().setProjectName(projectname) ;
		
		
		if ((sourceForProperties.length()==0) || ( docoProperties.isInitializationOK()==false )){
		
			docoPropertiesDefaults = new DocoPropertiesHandler(docoProperties);
			
			explicitlySettingProperties();
			 
		}

		docoFactory = DocumentObserverFactory.getInstance(docoProperties);   // creating the factory; 	
					  LogControl.Level = logLevel;	
					  docoFactory.getOut().setLogControlLevel(logLevel); 
		
		docoFactory.saveStartupTrace( instanceType, 
									  docoPropertiesDefaults.getStartupTraceInfo() );

		// now we could save the settings for ensuring smooth restart capabilities
		
		docoProperties.save();
		

		docoFactory.setArguments(appArguments) ;
			
		docoFactory.setUseStopfile(true);

	}

	private String adjustSystemRootFolder(String systemroot , String namepattern) {
		// 

		if (DFutils.folderExists(homedir)==false){
			return systemroot;
		}
		if (systemroot==null){
			systemroot = "/";
		}
		if ((systemroot.length()<=3) || 
			(DFutils.folderExists(systemroot)==false) || 
			(systemroot.toLowerCase().indexOf("/"+namepattern)<=3)){
			// systemroot = (new PathFinder()).getAppBinPath( this.getClass(), false);
			// systemroot = DFutils.getParentDir(systemroot) ;
			
			systemroot = homedir;
			
			String binpath = DFutils.getParentDir(systemroot,2);
			binpath = DFutils.createPath(binpath, "bin/") ;
			
			IniProperties.fluidSomProjectBasePath = binpath;
			IniProperties.saveIniProperties() ;
			
			// docoProperties.getSystemRootDir();
			docoProperties.setSystemRootDir(systemroot) ;
			// docoProperties.getPersistenceSettings().setPathToSomFluidSystemRootDir(systemroot) ;
		}

		
		return systemroot;
	}


	private void createStartTask( ) throws Exception{
		
		int processCount = 0;
		processControl = docoFactory.getDocoProcessControl() ;
		processCount = docoFactory.startDocumentObserver( instanceType, this );
		
		if (processCount>0){
			confirmStartupCompletion( processCount, "" );
		}
	}
	
	
	
	private void explicitlySettingProperties(){
		
		PersistenceSettings ps;


		
		try {
			// important to identify the startup trace... and persistence setting
			String instance = "doco";

			if (instanceType<=0){
				// instanceType = dc.
			}
			
			docoPropertiesDefaults.setInstance( instance ,0 ); 
			
			docoPropertiesDefaults.setConfigFile( IniProperties.dataSource);

			
			docoPropertiesDefaults.initializeDefaults();
			// loading xml, check texx for reading this stuff
			docoPropertiesDefaults.initializeDefaultsFromFile( IniProperties.dataSource ) ;
			

			
			// controlling the granularity/verbosity of console messages 
			if (LogControl.Level>2){
				docoProperties.setShowDocoProgress( DocumentObserverProperties._DOCO_DISPLAY_PROGRESS_STEPS ) ; // default: _SOMDISPLAY_PROGRESS_BASIC
			}
			docoProperties.setShowDocoProgress( DocumentObserverProperties._DOCO_DISPLAY_PROGRESS_STEPS );
			
			docoProperties.setMultiProcessingLevel(0); 
			
			// if we set this to true, we have to restart the observer from time to time, once each day or so
			docoProperties.setObserveOnlyUsedDirectories( true ) ;
			
			DocoControlProperties dc = docoProperties.getControlProperties();
			dc.readSettings(""); // if no file is given, the default name and location will be assumed
			
			
		} catch (Exception e) {
			e.printStackTrace();
			System.err.println("The system will exit.");
			System.exit(-7) ;
		}
		
		// set ready flag
		docoProperties.setInitializationOK(true) ;						
	}
	
	public void addRecord(){
		DocoDataBase docoDataBase = docoFactory.getDocoDataBase();
		//docoDataBase.addTestRecord();
	}


	@Override
	public void setChangeEventCount(int count) {
		
	}


	@Override
	public void setNotifications(String[] changetypes) {
		
	}


	@Override
	public void setLastRecordedChange(FileChangeIntf change) {

		String changeDescr , currFilename, prevFilename;
		
		changeDescr = change.getDescriptiveLabel() ;
		currFilename = change.getUpdatedFilename() ; 
		prevFilename = change.getPreviousFilename() ;
		
		PrintLog.Print(3,"       change: "+changeDescr+" to file : "+currFilename);

	}

	
	class OrganizedShutDown implements Runnable {
		
		Thread mainThread;
		Thread orgshut;
		
		public OrganizedShutDown(Thread mainThread){
			this.mainThread = mainThread;
			doit();
			orgshut = new Thread(this,"orgshut") ;
			orgshut.start();
		}
		
		private void doit(){
			
		
			Runtime.getRuntime()
		       .addShutdownHook(
				   new Thread() {
					  public void run() {
									      try {
									    	  keepRunning = false;
									    	  PrintLog.Print(1, "shutting down...");
									      } catch (Exception e) {
									      }
					  					}
							  });
		}
		private void waitTill(){
			
			PrintLog.Print(1, "now waiting...");
			while (keepRunning) {
				PrintLog.Delay(100);
			}

			PrintLog.Print(1, "now closing...");
			docoFactory.close();

			try {
				keepRunning = false;
				mainThread.join();
			} catch (Exception e) {
			}
			System.exit(2);
		}

		@Override
		public void run() {
			waitTill();
		}
	}



}

 


 